<?php
define("VERSION", "1.0.0.57");
define("DEBUG", false);
define("__ROOT__", __DIR__ . '/');
if (substr(PHP_VERSION, 0, 3) < 7) {
    throwerror(null, "index.php", 0, "php版本必须在7.0及以上");
}
//if(!file_exists("logs")){mkdir("logs",0777,true);}
// 注册全局队列
$__shutdown_call_list = [];
$__listen_error=true;
if($__listen_error){
error_reporting(0);
set_error_handler(function ($error_no, $error_str, $error_file, $error_line) {
    throwerror(null, $error_file, $error_line, $error_str);
}, E_ERROR);

register_shutdown_function(function () {
    global $__shutdown_call_list;
    for ($i = 0; $i < count($__shutdown_call_list); $i++) {
        $value = $__shutdown_call_list[$i];
        if ($value == null) continue;
        if (is_array($value) && count($value) > 0) {
            if (count($value) == 1) {
                $value = $value[0];
            } else {
                // $value[0]
                try {
                    ($value[0]->$value[1])();
                    continue;
                } catch (Exception $e) {
                }
            }
        }

        if (is_callable($value)) {
            try {
                $value();
            } catch (Exception $e) {
            }
        }
    }

    $error = error_get_last();

    if ($error && $error['type'] === E_ERROR) {
        //$errno   = $error["type"];

        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];
        throwerror(null, $errfile, $errline, $errstr);
    } else if ($error) {
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];
        $l = explode("\n", $errstr);
        if (count($l) > 1) $msg = $l[0];
        // print_r($error);
        $text=var_dump($error);
        $GLOBALS["app"]->log("[warning] \n$errfile[$errline]$errstr\n$text");
    }
});
}
/**
 * 添加在最后程序运行完的释放资源的语句。
 */
function add_shutdownList($call)
{
    global $__shutdown_call_list;
    $__shutdown_call_list[] = $call;
}
function loadscript($file)
{
    try {
        require_once($file);
    } catch (\Exception $exception) {
        //echo var_export($exception, true) . PHP_EOL;
    } catch (\Error $error) {
        //echo var_export($error, true) . PHP_EOL;
        //echo $error->getMessage();
        throwerror($error);
        return false;
    }
    return true;
}
function throwerror($error, $file = "", $line = 0, $msg = "")
{

    if ($error != null) {
        $file = $error->getFile();
        $line = $error->getLine();
        $msg = $error->getMessage();
    }
    $l = explode("\n", $msg);
    if (count($l) > 1) $msg = $l[0];
    // file_put_contents(__ROOT__."data/error.txt","[$line]$msg",FILE_APPEND);
    if ($GLOBALS["app"] instanceof Applications) {
        $GLOBALS["app"]->log("error \n[$line]$msg");
    }
    if (isAjax()) {
        $json["msg"] = "[$line]$msg";
        $json["code"] = 500;
        echo json_encode($json);
        exit;
    }

    $data = "<a style='color:red'>加载插件出错</a><style>tr:nth-child(odd){background:#F4F4F4;} table,td{border: 1px solid #F4F4F4;border-spacing:0px}</style><table>";
    $data .= "<tr><td>文件名</td><td>" . basename($file) . "</td></tr>";
    $data .= "<tr><td>目录</td><td>" . dirname($file) . "</td></tr>";
    $data .= "<tr><td>报错起始行</td><td>" . $line . "</td></tr>";
    $data .= "<tr><td>报错内容</td><td>" . $msg . "</td></tr>";
    $data .= "</table>";
    echo $data;
    echo PHP_EOL;
    exit;
}
function isAjax()
{
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
        return true;
    } else {
        return false;
    }
}
function full_reforward($ip = "")
{
    $header = get_all_headers();
    $post = file_get_contents('php://input');
    return curl_post_real($ip != "" ? $ip : $_SERVER['HTTP_HOST'], $_SERVER['HTTP_HOST'], $_SERVER["SERVER_PORT"], $_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD'], $post, $header);
}
function curl_post($domain, $port = 80, $url, $type, $data = array(), $header = array())
{
    return curl_post_real($domain, $domain, $port, $url, $type, $data, $header);
}
function curl_post_real($ip, $domain, $port = 80, $url, $type, $data = array(), $header = array(), $protocol = null, &$retHead = null)
{
    $ch = curl_init();
    $protocol = $protocol = "" ? null : $protocol;
    $ispost = $type == "POST";
    if (!$protocol) {
        if ($port == 443) {
            $protocol = "https";
        } else {
            $protocol = "http";
        }
    }

    if (($port == 443 && $protocol == "https") || ($port == 80 && $protocol == "http")) $port = "";
    if ($port != "") {
        $port = ":" . $port;
    }
    $url = $protocol . "://" . $ip . $port . $url;
    //file_put_contents(__ROOT__."log.txt",$url."\r\n");
    /*if ($port == 80) {
    $url = "http://" . $ip . $url;
} else if ($port == 443) {
    $url = "https://" . $ip . $url;
} else {
    $url = "http://" . $ip . ":" . $port . $url;
}*/
    $header[] = "Host: " . $domain . $port;
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_ENCODING, "gzip");
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    if ($ispost) {
        curl_setopt($ch, CURLOPT_POST, 1); // POST数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 把post的变量加上
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    $output = curl_exec($ch);
    if ($retHead !== null) $retHead = curl_getinfo($ch);
    
    curl_close($ch);
    return $output;
}

/**
 * 包含HTTP协议头部的
 */
function curl_post_real_full($ip, $domain, $port = 80, $url, $type, $data = array(), $header = array(), $protocol = null)
{
    $ch = curl_init();
    $protocol = $protocol = "" ? null : $protocol;
    $ispost = $type == "POST";
    if (!$protocol) {
        if ($port == 443) {
            $protocol = "https";
        } else {
            $protocol = "http";
        }
    }

    if (($port == 443 && $protocol == "https") || ($port == 80 && $protocol == "http")) $port = "";
    if ($port != "") {
        $port = ":" . $port;
    }

    if (strpos($ip, ":") === false) $ip = $ip . $port;


    $url = $protocol . "://" . $ip . $url;
    // var_dump($url);
    //file_put_contents(__ROOT__."log.txt",$url."\r\n");
    /*if ($port == 80) {
    $url = "http://" . $ip . $url;
} else if ($port == 443) {
    $url = "https://" . $ip . $url;
} else {
    $url = "http://" . $ip . ":" . $port . $url;
}*/
    $header[] = "Host: " . $domain . $port;
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_ENCODING, "gzip");
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    if ($ispost) {
        curl_setopt($ch, CURLOPT_POST, 1); // POST数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 把post的变量加上
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_HEADER, true); //最重要的一步，获取头部

    $output = curl_exec($ch);
    //$retHead = curl_getinfo($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    // 根据头大小去获取头信息内容
    $header = substr($output, 0, $headerSize);
    $output = substr_replace($output, "", 0, $headerSize);
    curl_close($ch);
    //print_r([$header,$output]);
    return [$header, $output];
}


function curl_post_simple($url, $data = array())
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_POST, 1); // POST数据
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 把post的变量加上
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}
function file_get_contents_post($url, $post)
{
    $options = array(
        'http' => array(
            'method' => 'POST',
            'header' => "Content-Type: application/json",
            'content' => http_build_query($post),
        ),
    );
    $result = file_get_contents($url, false, stream_context_create($options));
    return $result;
}
function curl_get_simple($url)
{
    $curl = curl_init(); //初始化
    curl_setopt($curl, CURLOPT_URL, $url); //设置url
    curl_setopt($curl, CURLOPT_HEADER, false); // 不返回HTTP头部信息
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // 设置获取的信息以文件流的形式返回
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    $data = curl_exec($curl); // 执行命令
    curl_close($curl); // 关闭URL请求
    return $data;
}
function nginx_get_all_headers()
{
    $headers = array();
    foreach ($_SERVER as $key => $value) {
        if (substr($key, 0, 5) === 'HTTP_') {
            $key = substr($key, 5);
            $key = strtolower($key);
            $key = str_replace('_', ' ', $key);
            $key = ucwords($key);
            $key = str_replace(' ', '-', $key);
            if ($key == "Content-Length" || $key == "User-Domain") {
                continue;
            }
            $headers[] = $key . ": " . $value;
        }
    }
    return $headers;
}
function  get_substring($str, $start_str, $stop_str, $n = 0)
{
    $start = $n;  //从第n个位置开始查找
    $start = strpos($str, $start_str, $start);
    $stop = strpos($str, $stop_str, $start + 1);
    if (!($start > -1 && $stop > -1)) return;
    $start = strlen($start_str) + $start;
    return substr($str, $start, $stop - $start);

    //return "";
}

function apache_get_all_headers()
{
    if (function_exists('apache_request_headers') && $result = getallheaders()) return $result;
}
function get_all_headers()
{
    if ($header = apache_get_all_headers()) $header = nginx_get_all_headers();
    $ret_header = [];
    foreach ($header as $key => $value) {
        if ((explode(": ", $value))[0] == "Host") {
            continue;
        }
        $ret_header[] = $value;
        # code...
    }
    return $ret_header;
}
function getcallname()
{ //获取上级调用的 函数名
    $backtrace = debug_backtrace();
    return $backtrace[2]["class"] . "->" . $backtrace[2]["function"];
}
function url_getfilename($url)
{
    if (strpos($url, "#") > 0) {
        $url = substr($url, 0, strpos($url, "#"));
    }
    if (strpos($url, "?") > 0) {
        $url = substr($url, 0, strpos($url, "?"));
    }
    return $url;
}
function startWith($str,$pattern) {
    return strpos($str,$pattern) === 0 ? true:false;
}

function App_run($app)
{
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Allow-Headers: Authorization, Content-Type, X-PINGOTHER,user-domain,*');
        header('Access-Control-Allow-Origin: *');
        return;
    }
    $args = $app->getArgs();
    $hook = $args["hook"];
    $extend = $args["extend"];
    $url = $_SERVER['REQUEST_URI'];
    if (strpos($url, "#") > 0) {
        $url = substr($url, 0, strpos($url, "#"));
    }
    if (strpos($url, "?") > 0) {
        $url = substr($url, 0, strpos($url, "?"));
    }
    $func = "";
    if (array_key_exists($url, $hook)) $func = $hook[$url];
    $data = "404 not found";
    do {
        if ($func != null && $func != "") {
            $data = $app->$func();
            // echo "$data";
            if ($data instanceof \string) {
                // $app->write($data);
                // $app->log("\$data instanceof \string")
                
            } else if (is_array($data)) {
                // $app->log("\$data instanceof \array");
                // $app->write();
                $data = json_encode($data, JSON_UNESCAPED_UNICODE);
                
            } else if ($data === false) {
                $data = $app->forword();
                // echo "dataE";
                // $data = "local serve data not reslove.";
            }
            
            // print("ec".$data);
            break;
        }
        foreach ($app->routeDir as $key => $value) {
            if (substr($url, 0, strlen($key)) == $key) {
                $data = $app->$value(substr($url, strlen($key)));
                if ($data === false) {
                    continue;
                }
                // return;
                break;
            }
        }
          
        $retvalue = false;
        if ($extend != null && $extend != "") {
            
            $retvalue = $app->$extend();
            if ($retvalue === true || $retvalue == null) return;
            if ($retvalue instanceof \string) {
                $data = $retvalue;
                break;
            }
            if (is_array($retvalue)) {
                $data = json_encode($data, JSON_UNESCAPED_UNICODE);
                break;
            }
        }else{
         
         $data = $app->forword(); //curl_post_real($app->ip, $app->host, $app->port, $app->url, $app->method, $app->post, $app->header);
        }
        
        
    } while (false);
    // print_r($data); 
    if ($data == null) return;
    
    $app->write($data);
}
function get_runtype()
{ //判断运行在哪个服务器下面，比如0.apache，1.nginx,2.iis
    $s = strtolower($_SERVER['SERVER_SOFTWARE']);
    if (strpos($s, "iis") > 0) {
        return 2;
    } else if (strpos($s, "apache")) {
        return 0;
    } else if (strpos($s, "nginx")) {
        return 1;
    }
    if (strpos(PHP_SAPI, "apache")) {
        return 0;
    } else {
        return 1;
    }
}
/**
 * 解析url中参数信息，返回参数数组
 */
function convertUrlQuery($query)
{

    if(strpos($query, '&') === false)return [];
    $queryParts = explode('&', $query);
    $params = array();
    // print_r($query);
    // print_r(count($queryParts));
    if(count($queryParts)>0)
    foreach ($queryParts as $param) {
        if($param=='')continue;
        $item = explode('=', $param);
        
        $params[$item[0]] = $item[1];
    }
    return $params;
}
class tool
{
    static $classlist = [];
    /**
     * 插件安装的主要函数
     * @param string $url
     * @return null
     */
    function plugin_install($url)
    {
        if (strtolower(substr($url, 0, 4)) == "http") {
            $data = curl_get_simple($url);
        } else if (strtolower(substr($url, 0, 9)) == "base64://") {
            $data = base64_decode(substr_replace($url, "", 0, 9));
        }

        //move_uploaded_file 请查阅相关资料，与文件上传有关，本框架暂时禁用
        $hookfunc = ['echo', 'var_dump', 'print_r', 'printf', 'move_uploaded_file']; //置为无效函数
        $hookfunc = array_merge($hookfunc, Applications_hook::$Applications_hook__operate_file_func); //合并父级的文件操作方法
        $source = $this->plugin_trpx($data, $hookfunc);
        //if(strpos($data))
        $data = [];
        $data["code"] = 404;
        do {
            if ($source == "") {
                $data["msg"] = "安装失败,因为下载插件失败或者解析失败";
                break;
            }
            if (strpos($source, "build") <= 0) {
                $data["msg"] = "没有找到build函数入口";
                break;
            }
            if (strpos($source, "extends \Applications") <= 0) {
                $data["msg"] = "没有找到继承Applications的类";
                break;
            }
            if (strpos($source, "getinfo") <= 0) {
                $data["msg"] = "没有找到getinfo()函数，无法获取插件信息。";
                break;
            }
            //if ($data != "" && strpos($data, "Applications") > 0) {
            /*$name=basename($url,".txt");
        if(substr($name,-3)!="php"){
            $name.=".php";
        }*/
            //__ROOT__."plugin/".$name
            //mkdir@()
            $file = __ROOT__ . "data/tmp_install.php";
            if (!file_put_contents($file, $source)) {
                $data["msg"] = "安装失败,写出数据失败";
                break;
            }

            $app = self::load_plugin($file);
            if ($app === false) {
                $data["msg"] = "插件解析失败!";
                break;
            }
            if (!method_exists(get_class($app), "build")) {
                $data["msg"] = "没有找到build函数入口";
                break;
            }
            if (!method_exists(get_class($app), "getinfo")) {
                $data["msg"] = "没有找到getinfo()函数，无法获取插件信息。";
                break;
            }

            $info = $app->getinfo();
            //return array("author" => "", "file" => '', "title" => "", "content" => "", "help_url" => "", "icon" => "", 'version' => '1.0.0.0');
            if ($info["file"] == "") {
                $data["msg"] = "插件名称获取失败!请在getinfo函数里面指定file字段";
                break;
            }
            if (preg_match('/^[\w.-]{1,}$/', $info["file"]) !== 1) {
                $data["msg"] = "getinfo函数file字段定义有误!";
                break;
            }
            if ($info["file"] == "core.php") {
                $data["msg"] = "内核文件禁止覆盖！";
                break;
            }
            if (!rename($file, __ROOT__ . "plugin/" . $info["file"])) {
                $data["msg"] = "安装插件出错，/plugin无写入权限!";
                break;
            }
            if (method_exists(get_class($app), "configure") && $defconfig = $app->configure()) {
                $out = "";
                foreach ($defconfig as $key => $value) {
                    $value = array_pad($value, 3, "");
                    $value[0] = (string)tool::convert_type($value[0]);
                    $out .= ($value[2] != "" ? "#" . $value[2] . "\n" : "") . $key . "=" . $value[0] . "\n";
                }

                //for($i=0;$i<count($defconfig);$i++)$out.=$defconfig[$i]["0"]."=".$defconfig[$i]["2"]."\n";
                $app->file_put_contents("app.ini", $out);
            }
            $data["code"] = 200;
            $name = $info["title"] . "[" . basename($info["file"], ".php") . "]:" . $info["version"];
            $data["msg"] = "安装" . $name . "成功!";
            $data["data"] = $app->getinfo();
            //$data = json_encode($data, JSON_UNESCAPED_UNICODE);
            //echo $data;
            //}else {
            //   $data["code"] = 404;
            //   $data["msg"] = "安装失败,写出数据失败";
            //throwerror(null,$url,0,"安装失败,写出数据失败"); 
            //}
            // } else {

            //    $data["code"] = 404;
            //    $data["msg"] = "安装失败,因为下载插件失败或者解析失败";
            //$data["code"]=404;
            //throwerror(null,$url,0,"安装失败,因为下载插件失败"); 
            //}
        } while (false);
        return $data;
    }
    static function get_all_reg_plugin_namespace()
    {
        $class = get_declared_classes();
        $out = self::$classlist;
        foreach ($class as $i => $v) {
            if (strpos($v, "Application") > 0 && get_parent_class($v) == "Applications" && !in_array($v, $out)) {
                $out[] = $v;
            }
        }
        if (self::$classlist != $out) self::$classlist = $out;
        return $out;
    }
    static function get_last_class($real_freash = false)
    {
        if ($real_freash) self::get_all_reg_plugin_namespace();
        return end(self::$classlist);
    }
    static function load_plugin($file)
    {
        include_once($file);
        $imclass = tool::get_last_class(true);
        if (!class_exists($imclass)) {
            return false;
        }
        return new $imclass();
    }
    /**
     * 插件解析
     */
    function plugin_trpx(string $content, array  $hookfunc): string
    {
        $stripStr = '';
        $tokens =   token_get_all($content);
        $last_space = false;
        for ($i = 0, $j = count($tokens); $i < $j; $i++) {
            if (is_string($tokens[$i])) {
                $last_space = false;
                $stripStr .= $tokens[$i];
            } else {
                switch ($tokens[$i][0]) {
                        //过滤各种PHP注释
                    case T_COMMENT:
                    case T_DOC_COMMENT:
                        break;
                        //过滤空格
                    case T_WHITESPACE:
                        if (!$last_space) {
                            $stripStr .= ' ';
                            $last_space = true;
                        }
                        break;
                    case T_ECHO:
                    case T_PRINT:
                    case T_EVAL:
                    case T_STRING: //代号319，有函数名称
                        if (in_array($tokens[$i][1], $hookfunc)) $tokens[$i][1] = '$this->' . $tokens[$i][1];
                        //case T_CONSTANT_ENCAPSED_STRING://表示是自定义的函数
                        //echo $tokens[$i][1]."\n<br>";

                        //$tokens[$i][1]=str_replace($tokens[$i][1]);
                    default:
                        $last_space = false;
                        $stripStr .= $tokens[$i][1];
                }
            }
        }
        return $stripStr;
    }
    static function convert_type($obj)
    {
        switch (gettype($obj)) {
            case "bool":
                return $obj ? 1 : 0;
            default:
                return $obj;
        }
    }
}
class Db
{
    private  static  $instance, $con;
    private $s, $u, $p, $dbn, $debug, $app, $lastSql;



    static function init(string $server, string $username, string $password, string $db = "")
    {
        return new \Db($server, $username, $password, $db);
    }

    function __construct(string $server, string $username, string $password, string $db = "")
    {
        $this->s = $server;
        $this->u = $username;
        $this->p = $password;
        $this->dbn = $db;
        self::$instance = $this;
    }

    function query($sql, ...$param)
    {
        $_sql = '';
        if (count($param) > 0) {
            $_par = [];
            for ($i = 0; $i < count($param); $i++) {
                $_par[] = mysqli_real_escape_string($this->con, $param[$i]);
            }
            $_sql = sprintf($sql, ...$_par);
        }else{
            $_sql=$sql;
        }
        $res=mysqli_query($this->con,$_sql);
        if($this->con->errno){
            // 查询出错。   
            return false;
        }
        $result=mysqli_fetch_all($res,MYSQLI_ASSOC);
        mysqli_free_result($res);
        return $result;

        // 未完待续
        // print($sql);
        //$data = mysqli_fetch_all($res,MYSQLI_ASSOC);
    }
    public function execute($sql, ...$param)
    {
        // echo "as";
        // $res = mysqli_query($this->con, $sql);
        $this->addMysqlLog($sql);
        $this->lastSql = $sql;
        try {
            $stmt = $this->con->prepare($sql);
            if(!$stmt){
                // mysql 语句解析错误
                // throw new Exception("sql error.");
                $this->addMysqlLog("sql error.");
                return false;
            }
            if (count($param) > 0) {
                $m_vlist = str_repeat("s", count($param));
                
                $stmt->bind_param($m_vlist, ...$param);
            }
            $stmt->execute();
            $result = (int)mysqli_affected_rows($this->con);
            // $result=$stmt->affected_row(); //影响的行数
            // echo "ok";
            // $result = $stmt->affected_row();
            $stmt->close();
            return $result;
        } catch (Exception $e) {
            // echo ($e->getMessage());

            $this->addMysqlLog($e->getMessage());
            return 0;
        }

        // 未完待续
        // print($sql);
        //$data = mysqli_fetch_all($res,MYSQLI_ASSOC);
    }
    function build()
    {
        $con = mysqli_connect("$this->s", "$this->u", "$this->p", "$this->dbn");
        if (mysqli_connect_errno($con)) {
            // 数据连接失败。
            // echo "连接数据库失败".mysqli_connect_error();
            return false;
        }
        $this->con = $con;
        return true;
    }
    function addMysqlLog($str)
    {
        if ($this->app instanceof Applications && $this->debug = true)
            $this->app->log("[Mysqli] $str.");
    }

    public static function __callStatic($name, $arguments)
    {
        if ($name == "q") {
            $name = "query";
        } else if ($name == "e" || $name == "exec") {
            $name = "execute";
        }
        if (self::$instance == null) {
            // 提示性报错，没有可用的示例，也就是没有配置数据。
            return false;
        }
        $ice = self::$instance;
        if (self::$con == null) {
            $bt = debug_backtrace();
            if ($ice->debug == null) if ($bt[1]["object"] instanceof Applications) {
                $ice->debug = ($bt[1]["object"])->debug;
            }
            if (!($ice->build())) {
                // 提示性错误。数据库连接失败

                $ice->addMysqlLog("数据库连接失败.");
                return false;
            } else {
                add_shutdownList($ice->con->close);
            }
        }
        if (method_exists($ice, $name)) {
            // echo "exits";
            $v = $ice->$name(...$arguments);
            // $v=call_user_func_array($ice->$name, $arguments);
            return $v;
        } else {
            // 提示性报错，调用的方法不存在。
            echo "method not found.";
            $ice->addMysqlLog($name . "方法不存在.");
            return false;
        }
    }
}
class Applications extends Applications_hook
{
    private $hook = [];
    public $routeDir = [];
    //环境类变量
    private $extend = "";
    public $ip;
    public $host;
    public $port;
    public $url;
    public $url_file;
    public $method;
    public $post;
    public $header;
    public $protocol = "http";
    public $debug = DEBUG;
    public $m_remote_server = "";
    public $retheader = [];
    public $config;
    /**
     * 本变量仅做获取操作，赋值无效，修改url参数请修改$url
     */
    public $param;


    //控制类变量
    public $is_WRITE_ONCE = false;
    function __construct()
    {
        $this->ip = $_SERVER["HTTP_USER_DOMAIN"] ?? $_SERVER['HTTP_HOST'];
        $this->host = $_SERVER["HTTP_USER_DOMAIN"] ?? $_SERVER['HTTP_HOST'];

        $this->port = $_SERVER['SERVER_PORT'];
        $this->url = $_SERVER['REQUEST_URI'];
        $this->method = $_SERVER['REQUEST_METHOD'];
        $this->post = file_get_contents('php://input');
        $this->header = get_all_headers();
        $this->url_file = url_getfilename($this->url);
        // print_r(parse_url($this->url));
        
        $tmpData=parse_url($this->url);
        // print_r(array_key_exists("query",$tmpData)==false);
        
        $this->param = convertUrlQuery(array_key_exists("query",$tmpData)?$tmpData['query']:"");

        $this->config = $this->file_exists('app.ini') ? $this->parse_ini_file('app.ini', false) : [];
        $this->debug = $this->config["debug"] ?? DEBUG;
        $this->protocol = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? "https" : "http";
    }
    final function run()
    {
        $GLOBALS["app"] = $this;
        return $this;
    }
    /**
     * 添加http头部信息
     * @param string $str
     */
    final function addheader($str)
    {
        $this->header[] = $str;
    }
    /**
     * 获取插件信息，给外部使用的，如果用户在子类上没有定义，则默认调用这里的函数
     */
    function getinfo()
    {
        return array("author" => "", "file" => '', "title" => "", "content" => "", "help_url" => "", "icon" => "", 'version' => '1.0.0.0');
    }
    /**
     * 设置远程服务器
     * @param string $url   远程服务器地址
     */
    final function remote_server($url)
    {
        $this->m_remote_server = $url;
    }
    final function forword()
    {
        $tmp_header = $this->genaskheader();
        if ($this->m_remote_server != "") {
            $data = json_decode(curl_post_simple($this->m_remote_server, json_encode([$this->ip, $this->host, $this->port, $this->url, $this->method, $this->post, $tmp_header, $this->protocol])), true);
        } else {
            // var_dump("real");
            $data = curl_post_real_full($this->ip, $this->host, $this->port, $this->url, $this->method, $this->post, $tmp_header, $this->protocol);
        }
        $this->retheader = explode("\n", str_replace("\r\n", "\n", $data[0]));
        //print_r($data);
        return $data[1];

        return curl_post_real($this->ip, $this->host, $this->port, $this->url, $this->method, $this->post, $tmp_header, $this->protocol, $this->retheader);
    }
    final function  getArgs()
    {
        return (array("app" => $this, "hook" => $this->hook, "extend" => ($this->extend)));
    }
    final function get($url)
    {
        if ($this->m_remote_server != "") {
            $url = parse_url($url);
            if (strpos($url["host"], ":") > 0) {
                $url["port"] = substr($url, strpos($url["host"], ":") - strlen($url));
                $url['host'] = substr($url['host'], 0, strpos($url["host"], ":"));
            } else {
                if ($url['scheme'] == "https") {
                    $url["port"] = 443;
                } else {
                    $url["port"] = 80;
                }
            }
            if ($url['scheme'] == "") {
                $url['scheme'] = "http";
            }
            return curl_post_simple($this->m_remote_server, json_encode([$url["host"], $url["host"], $url["port"], $url['path'] . '?' . $url['query'], 0, "", ""]));
        }
        $data = curl_get_simple($url);
        return $data;
    }

    final function route($url, $func = "SAME_URL_METHOD")
    {
        if ($func == "SAME_URL_METHOD") {
            $func = basename($url);
            if ($func == "") return;
        }
        $this->hook[$url] = $func;
        return $this;
    }
    final function routeDir($url, $func)
    {
        $this->routeDir[$url] = $func;
        return $this;
    }
    final function full($func)
    {
        $this->extend = $func;
        return $this;
    }
    final function default($func)
    {
        $this->extend = $func;
        return $this;
    }
    /**
     * 写出数据（常规），如果开启debug模式。那么会被记录进日志
     */
    final function write($data)
    {
        if (is_array($data)) {
            $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        }
        //print_r(array($this->retheader,$data));
        if ($this->is_WRITE_ONCE === false) {
            foreach ($this->retheader as $key => $value) {
                if (strpos($value, "Content-Encoding") !== false) {
                    continue;
                }
                if (strpos($value, "Transfer-Encoding") !== false) {
                    continue;
                }

                if (trim($value) == "") continue;
                header($value);
            }
            header("FrameVersion: " . VERSION);
            $this->is_WRITE_ONCE = true;
        }

    
    
        $wrt_data=$data;
        if(strpos($this->url,"/favicon.ico")!==false){$wrt_data="[已隐藏图标数据]";}    
        if ($this->debug) $this->file_put_contents("/logs.txt", $this->method . " " . $this->protocol . "://" . $this->ip . ":" . $this->port . $this->url . "\n" . json_encode($this->genaskheader()) . "\n----------------\n" . $this->post . "\n\n============================\n" . join("\r\n", $this->retheader) . "\r\n" . $wrt_data . "\n==============================\n", FILE_APPEND);
        echo $data;
    }
    final function log($str)
    {
        $this->file_put_contents("/logs.txt", "\r\n***********************\r\n[log]:" . $str . "\r\n***********************\r\n", FILE_APPEND);
    }
    final function genaskheader()
    {
        $port = $this->port;
        if (($this->port == 443 && $this->protocol == "https") || ($this->port == 80 && $this->protocol == "http")) $port = "";
        if ($port != "") {
            $port = ":" . $port;
        }
        $tmp_header = $this->header;
        array_push($tmp_header, "Host: " . $this->host . $port);
        ///return array(...,"Host: ".$this->host.$port);
        return $tmp_header;
    }

    function configure()
    {
        //{配置项:[配置项默认值【可选，默认为空】,配置项的类型【可选，默认为string】,配置项说明【可选，默认为空】],[第二个配置信息]}
        return array("debug" => array(
            true, "bool", "debug模式"
        ));
    }
    final function set($key, $v)
    {
        $this->$key = $v;
        return $this;
    }
}
class Applications_hook
{

    private $Applications_hook__dir = ""; //给方法getFile_convent用的
    //private $appinfo=[];
    private $app_filename;
    static $Applications_hook__operate_file_func = [
        "file_get_contents", "file_put_contents", "fopen", "popen", 'chmod', 'file', 'file_exists', 'filesize', "filetype",
        'unlink', 'parse_ini_file', 'pathinfo', 'realpath', 'rename', 'mkdir', 'rmdir', 'touch', 'scandir', 'opendir', 'is_dir', 'is_executable', 'is_file', 'is_link', 'is_readable', 'is_uploaded_file', 'is_writable', "parse_ini_file",'dir'
    ]; //HOOK文件操作部分

    function __call($name, $args)
    {
        if (!isset($this->appinfo)) {
            
            $this->app_filename = basename(($this->getinfo())["file"], ".php");
            // print_r(($this->getinfo()));
            $this->app_filename=strlen($this->app_filename)>0?$this->app_filename:($_SERVER["HTTP_USER_DOMAIN"]??$_SERVER['HTTP_HOST']);
            // print_r($this->app_filename);
            if ($this->app_filename == "") {
                $this->app_filename = "tmp";
                
            }
        }else{
            
            $this->app_filename =$this->host;
        }
        
        
        //$this->appinfo=$this->appinfo??$this->appinfo=$this->getinfo();
        if ($name == "rename") {
            $args[1] = $this->getFile_convent($args[1]);
        }
        else if ($name == "parse_ini_file") {
            $args[1] = $args[1] ?? false;
        }
        else if(startWith($name,'set_') && property_exists($this,str_replace("set_","",$name))){
            if(count($args)==0){return this;}// 应该让其报错。
            $key=str_replace("set_","",$name);
            // var_dump($key);
            // var_dump( $this->$key);
            // var_dump($args);
            $this->$key=$args[0];
        }
        else if (in_array($name, self::$Applications_hook__operate_file_func)) {
            $args[0] = $this->getFile_convent($args[0]);
            // if($name=="file_put_contents")print_r($args[0]);
            return $name(...$args);
        }
        
        return $this;
    }
    final private function getFile_convent($file)
    {
        if (substr(strtolower($file), 7) == "http://") {
            return $file;
        }
        if ($this->Applications_hook__dir == "") {
            $dir = __ROOT__ . "data/" . $this->app_filename . "/";
            if (!file_exists($dir)) mkdir($dir, 0777, true);
            $this->Applications_hook__dir = $dir;
        } else {
            $dir = $this->Applications_hook__dir;
        }
        $file = $dir . $file;
        $file = str_replace("\\", "/", $file);
        $file = str_replace("../", "/", $file);
        $file = str_replace(".../", "/", $file);
        $file = str_replace("//", "/", $file);
        return $file;
    }
}
